From 65fbb3b646de3c7c7613832ce90cdc7f998438ac Mon Sep 17 00:00:00 2001 From: "kaf24@firebug.cl.cam.ac.uk" Date: Sat, 22 Apr 2006 10:41:53 +0100 Subject: [PATCH] The Xen checksum offload feature attempts to insert a TCP/UDP checksums into already encrypted packets (esp4) in dom0. Obviously, it is not possible to insert a checksum into an already encrypted packet, so this patch inserts the checksum prior to encrypting packets in net/ipv4/xfrm4_output.c. To do this cleanly, the TCP/UDP header pointers need to be pointed to the correct spot, so this functionality has been abstracted into a new function. This patch fixes bug 143 (verified by Jim Dykman). Earlier version verified by Jon McCune. Signed-off-by: James Dykman Signed-off-by: Jon Mason --- linux-2.6-xen-sparse/net/core/dev.c | 76 +++++++++++++++++------------ patches/linux-2.6.16/net-csum.patch | 23 +++++++++ 2 files changed, 67 insertions(+), 32 deletions(-) diff --git a/linux-2.6-xen-sparse/net/core/dev.c b/linux-2.6-xen-sparse/net/core/dev.c index e526fccc2f..492fb7c800 100644 --- a/linux-2.6-xen-sparse/net/core/dev.c +++ b/linux-2.6-xen-sparse/net/core/dev.c @@ -1220,6 +1220,43 @@ int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask) } \ } +#ifdef CONFIG_XEN +inline int skb_checksum_setup(struct sk_buff *skb) +{ + if (skb->proto_csum_blank) { + if (skb->protocol != htons(ETH_P_IP)) + goto out; + skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl; + if (skb->h.raw >= skb->tail) + goto out; + switch (skb->nh.iph->protocol) { + case IPPROTO_TCP: + skb->csum = offsetof(struct tcphdr, check); + break; + case IPPROTO_UDP: + skb->csum = offsetof(struct udphdr, check); + break; + default: + if (net_ratelimit()) + printk(KERN_ERR "Attempting to checksum a non-" + "TCP/UDP packet, dropping a protocol" + " %d packet", skb->nh.iph->protocol); + goto out; + } + if ((skb->h.raw + skb->csum + 2) > skb->tail) + goto out; + skb->ip_summed = CHECKSUM_HW; + skb->proto_csum_blank = 0; + } + return 0; +out: + return -EPROTO; +} +#else +inline int skb_checksum_setup(struct sk_buff *skb) {} +#endif + + /** * dev_queue_xmit - transmit a buffer * @skb: buffer to transmit @@ -1266,38 +1303,12 @@ int dev_queue_xmit(struct sk_buff *skb) __skb_linearize(skb, GFP_ATOMIC)) goto out_kfree_skb; -#ifdef CONFIG_XEN - /* If a checksum-deferred packet is forwarded to a device that needs a - * checksum, correct the pointers and force checksumming. - */ - if (skb->proto_csum_blank) { - if (skb->protocol != htons(ETH_P_IP)) - goto out_kfree_skb; - skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl; - if (skb->h.raw >= skb->tail) - goto out_kfree_skb; - switch (skb->nh.iph->protocol) { - case IPPROTO_TCP: - skb->csum = offsetof(struct tcphdr, check); - break; - case IPPROTO_UDP: - skb->csum = offsetof(struct udphdr, check); - break; - default: - if (net_ratelimit()) - printk(KERN_ERR "Attempting to checksum a non-" - "TCP/UDP packet, dropping a protocol" - " %d packet", skb->nh.iph->protocol); - rc = -EPROTO; - goto out_kfree_skb; - } - if ((skb->h.raw + skb->csum + 2) > skb->tail) - goto out_kfree_skb; - skb->ip_summed = CHECKSUM_HW; - skb->proto_csum_blank = 0; - } -#endif - + /* If a checksum-deferred packet is forwarded to a device that needs a + * checksum, correct the pointers and force checksumming. + */ + if(skb_checksum_setup(skb)) + goto out_kfree_skb; + /* If packet is not checksummed and device does not support * checksumming for this protocol, complete checksumming here. */ @@ -3351,6 +3362,7 @@ EXPORT_SYMBOL(unregister_netdevice_notifier); EXPORT_SYMBOL(net_enable_timestamp); EXPORT_SYMBOL(net_disable_timestamp); EXPORT_SYMBOL(dev_get_flags); +EXPORT_SYMBOL(skb_checksum_setup); #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) EXPORT_SYMBOL(br_handle_frame_hook); diff --git a/patches/linux-2.6.16/net-csum.patch b/patches/linux-2.6.16/net-csum.patch index d6ede6b258..6543dcc47b 100644 --- a/patches/linux-2.6.16/net-csum.patch +++ b/patches/linux-2.6.16/net-csum.patch @@ -39,3 +39,26 @@ diff -pruN ../pristine-linux-2.6.16/net/ipv4/netfilter/ip_nat_proto_udp.c ./net/ *portptr = newport; return 1; } +diff -r 601fa226a761 net/ipv4/xfrm4_output.c +--- a/net/ipv4/xfrm4_output.c Wed Apr 19 18:52:30 2006 ++++ b/net/ipv4/xfrm4_output.c Thu Apr 20 15:49:40 2006 +@@ -16,6 +16,8 @@ + #include + #include + #include ++ ++extern int skb_checksum_setup(struct sk_buff *skb); + + /* Add encapsulation header. + * +@@ -103,6 +105,10 @@ + struct xfrm_state *x = dst->xfrm; + int err; + ++ err = skb_checksum_setup(skb); ++ if (err) ++ goto error_nolock; ++ + if (skb->ip_summed == CHECKSUM_HW) { + err = skb_checksum_help(skb, 0); + if (err) -- 2.30.2